#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QFileDialog>
#include <QToolBar>

#include "mainwindow.h"

#define  PROGRAM_NAME "Simulator"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setWindowTitle(tr(PROGRAM_NAME)+" (blink.binary)");

    QMenu *file = new QMenu(tr("File"), this);
    QMenu *run = new QMenu(tr("Run"), this);

    //menuBar()->addMenu(file);
    //menuBar()->addMenu(run);

    file->addAction(tr("Load"), this, SLOT(load()), QKeySequence::Open);
    run->addAction(tr("Run"), &w, SLOT(start()), Qt::Key_F8);
    run->addAction(tr("Debug"), &w, SLOT(debug()), Qt::Key_F8);
    run->addAction(tr("Reset"), &w, SLOT(reset()), Qt::Key_F9);
    run->addAction(tr("Step"), &w, SLOT(step()), Qt::Key_F10);
    run->addAction(tr("Stop"), &w, SLOT(stop()), Qt::Key_F12);


    fileToolBar = addToolBar(tr("Program"));
    fileToolBar->setToolTip(tr("Program Tools"));

    loadButton = new QAction(tr("Load"), this);
    connect(loadButton,SIGNAL(triggered()), this, SLOT(load()));
    loadButton->setToolTip(tr("Load another program binary."));
    fileToolBar->addAction(loadButton);

    runButton = new QAction(tr("Run"), this);
    connect(runButton,SIGNAL(triggered()), this, SLOT(start()));
    runButton->setToolTip(tr("Run program with near real-time effects."));
    fileToolBar->addAction(runButton);

    debugToolBar = addToolBar(tr("Debugger"));
    debugToolBar->setToolTip(tr("Debug Tools"));

    debugButton = new QAction(tr("Debug"), this);
    connect(debugButton,SIGNAL(triggered()), this, SLOT(debug()));
    debugButton->setToolTip(tr("Step through program."));
    debugToolBar->addAction(debugButton);

    stopButton = new QAction(tr("Stop"), this);
    connect(stopButton,SIGNAL(triggered()), this, SLOT(stop()));
    stopButton->setToolTip(tr("Stop Run or Debug"));
    debugToolBar->addAction(stopButton);

#if 0
    // Continue is the same as Debug
    contButton = new QAction(tr("Continue"), this);
    connect(contButton,SIGNAL(triggered()), this, SLOT(cont()));
    debugToolBar->addAction(contButton);
#endif

    stepButton = new QAction(tr("Step"), this);
    connect(stepButton,SIGNAL(triggered()), this, SLOT(step()));
    stepButton->setToolTip(tr("Step to the next line in all cores"));
    debugToolBar->addAction(stepButton);

    delayButton = new QAction(tr("Delay"), this);
    connect(delayButton,SIGNAL(triggered()), this, SLOT(delay()));
    delayButton->setToolTip(tr("Set delay between steps in debug"));
    debugToolBar->addAction(delayButton);

    resetButton = new QAction(tr("Reset"), this);
    connect(resetButton,SIGNAL(triggered()),this, SLOT(reset()));
    resetButton->setToolTip(tr("Restart loaded program"));
    debugToolBar->addAction(resetButton);

    traceButton = new QAction(tr("Trace"), this);
    connect(traceButton,SIGNAL(triggered()), this, SLOT(trace()));
    traceButton->setToolTip(tr("Show trace window"));
    debugToolBar->addAction(traceButton);

    breakToolBar = addToolBar(tr("Breakpoints"));
    breakToolBar->setToolTip(tr("Breakpoint Tools"));

    clearBreakButton = new QAction(tr("Clear"), this);
    connect(clearBreakButton,SIGNAL(triggered()), &w, SLOT(clearBreakpoints()));
    clearBreakButton->setToolTip(tr("Clear all breakpoints"));
    breakToolBar->addAction(clearBreakButton);

    showBreakButton = new QAction(tr("Show"), this);
    connect(showBreakButton,SIGNAL(triggered()), &w, SLOT(showBreakpoints()));
    showBreakButton->setToolTip(tr("Show next breakpoint"));
    breakToolBar->addAction(showBreakButton);

    newBreakButton = new QAction(tr("New"), this);
    connect(newBreakButton,SIGNAL(toggled(bool)), &w, SLOT(newBreak(bool)));
    newBreakButton->setToolTip(tr("Break on new core init"));
    newBreakButton->setCheckable(true);
    breakToolBar->addAction(newBreakButton);

    setCentralWidget(&w);
    setMaximumWidth(w.width());
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    w.stop();
    if(e) e->accept();
    qApp->exit(0);
}


void MainWindow::load()
{
    w.stop();
    QString name = QFileDialog::getOpenFileName(this, tr("Load Binary File"), lastdir, "*.binary");
    lastdir = name.mid(0,name.lastIndexOf("/"));
    QFile file(name);
    if(file.open(QFile::ReadOnly)) {
        program = file.readAll();
        w.load(program);
        file.close();
        name = name.mid(name.lastIndexOf("/")+1);
        this->setWindowTitle(tr(PROGRAM_NAME)+" ("+name+")");
    }
}

void MainWindow::cont()
{
    fileToolBar->setVisible(false);
    w.cont();
}

void MainWindow::debug()
{
    fileToolBar->setVisible(true);
    runButton->setVisible(true);
    //contButton->setVisible(true);
    stepButton->setVisible(true);
    resetButton->setVisible(true);
    delayButton->setVisible(true);
    traceButton->setVisible(true);
    breakToolBar->setVisible(true);

    w.debug();
}

void MainWindow::delay()
{
    w.delay();
}

void MainWindow::reset()
{
    w.reset();
    w.load(program);
}

void MainWindow::start()
{
    fileToolBar->setVisible(false);
    debugButton->setVisible(false);
    //contButton->setVisible(false);
    stepButton->setVisible(false);
    resetButton->setVisible(false);
    delayButton->setVisible(false);
    traceButton->setVisible(false);
    breakToolBar->setVisible(false);
    w.start();
}

void MainWindow::stop()
{
    fileToolBar->setVisible(true);
    debugButton->setVisible(true);
    runButton->setVisible(true);
    //contButton->setVisible(true);
    stepButton->setVisible(true);
    resetButton->setVisible(true);
    delayButton->setVisible(true);
    traceButton->setVisible(true);
    breakToolBar->setVisible(true);
    w.stop();
}

void MainWindow::step()
{
    w.step();
}

void MainWindow::trace()
{
    w.showTrace(true);
}
